﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NeuralStock.DomainService.Interfaces;
using NeuralStock.Entities;
using NeuralStock.Common;
using NeuralStock.DataAccess;
using NeuralStock.Tools;

namespace NeuralStock.DomainService.Implementation
{
    public class FinancialAnalysisService : BaseService, IFinancialAnalysisService
    {
        private readonly ICompanyService companyService;
        private readonly ICompanyQuotationService companyQuotationService;
        private readonly IFinancialReportService financialReportService;
        
        public FinancialAnalysisService(ICompanyService companyService, ICompanyQuotationService quotationService, IFinancialReportService financialReportService)
        {
            this.companyService = companyService;
            this.companyQuotationService = quotationService;
            this.financialReportService = financialReportService;
        }

        public FinancialAnalysisResult PrepareFull(int companyId, int year)
        {
            FinancialAnalysisResult result = new FinancialAnalysisResult();

            result.EbitdaReturnOnEquityCapital_Vs3YearAvg = CalculateEbitReturnOnEquityCapitalVs3YearAvg(companyId, year);
            result.ParticipationOfEquityCapitalInAssets_Vs3YearAvg = CalculateParticipationOfEquityCapitalInAssetsVs3YearAvg(companyId, year);

            result.AnalysisResult = false;
            if (ValidateLackOfNumberOfSharesShocks(companyId))
            {
                // todo: JR here should be added additional analysis
                result.AnalysisResult = true;
            }

            return result;
        }

        public decimal? CalculateEbitReturnOnEquityCapital(int companyId, int year)
        {
            var report = financialReportService.Get(companyId, year);

            return report.ProfitFromOperatingActivities / report.EquityCapital;
        }

        public decimal? CalculateEbitReturnOnEquityCapitalVs3YearAvg(int companyId, int year)
        {
            var currentValue = CalculateEbitReturnOnEquityCapital(companyId, year);
            var pastValues = new List<decimal?>();
            for (int pastYear = year - 3; pastYear <= year - 1; pastYear++)
            {
                pastValues.Add(CalculateEbitReturnOnEquityCapital(companyId, pastYear));
            }

            return CalculateValueVsItsAvg(currentValue, pastValues);
        }

        public decimal? CalculateParticipationOfEquityCapitalInAssets(int companyId, int year)
        {
            var report = financialReportService.Get(companyId, year);

            return report.EquityCapital / report.Assets;
        }

        public decimal? CalculateParticipationOfEquityCapitalInAssetsVs3YearAvg(int companyId, int year)
        {
            var currentValue = CalculateParticipationOfEquityCapitalInAssets(companyId, year);
            var pastValues = new List<decimal?>();
            for (int pastYear = year - 3; pastYear <= year - 1; pastYear++)
            {
                pastValues.Add(CalculateParticipationOfEquityCapitalInAssets(companyId, pastYear));
            }

            return CalculateValueVsItsAvg(currentValue, pastValues);
        }

        public bool ValidateLackOfNumberOfSharesShocks(int companyId)
        {
            var reports = financialReportService.GetAllForCompany(companyId);

            var numberOfShares = reports.Select(x => x.NumberOfShares).ToList();

            if ((numberOfShares.Max().Value / numberOfShares.Min().Value) > 10.0m)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        private decimal? CalculateValueVsItsAvg(decimal? value, List<decimal?> avg)
        {
            return value / avg.Average();
        }

        private bool RateValue(decimal? value, decimal? lowerLimit, decimal? upperLimit)
        {
            if (value.HasValue)
            {
                if (lowerLimit.HasValue
                    && value < lowerLimit)
                {
                    return false;
                }

                if (upperLimit.HasValue
                    && value > upperLimit)
                {
                    return false;
                }
                return true;
            }
            return false;
        }
    }
}
